package www.ash.com;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;

/**
 * @author : Chen Chao
 * @encoding : UTF-8
 * @date : 2021/9/30 16:54
 * @file : mySnake.www.ash.com.MyPanel.java
 * @software : IntelliJ IDEA
 * @since : 1.8
 */
public class MyPanel extends JPanel implements KeyListener, ActionListener {
    /**
     * 贪吃蛇图片位置
     */
    public static final String IMAGE_PATH = "src/main/resources/image/";
    /**
     * 蛇头向右边
     */
    public static final ImageIcon RIGHT = new ImageIcon(IMAGE_PATH + "right.png");
    /**
     * 蛇头向左边
     */
    public static final ImageIcon LEFT = new ImageIcon(IMAGE_PATH + "left.png");
    /**
     * 蛇头向上边
     */
    public static final ImageIcon UP = new ImageIcon(IMAGE_PATH + "top.png");
    /**
     * 蛇头向下边
     */
    public static final ImageIcon DOWN = new ImageIcon(IMAGE_PATH + "bottom.png");
    /**
     * 蛇身体
     */
    public static final ImageIcon BODY = new ImageIcon(IMAGE_PATH + "body.png");
    /**
     * 食物
     */
    public static final ImageIcon FOOD = new ImageIcon(IMAGE_PATH + "food.png");
    /**
     * 游戏屏幕宽度
     */
    public static final Integer GAME_WIDTH = 700;
    /**
     * 游戏屏幕高度
     */
    public static final Integer GAME_HEIGHT = 900;
    /**
     * 游戏结束蛇的长度
     */
    public static final Integer GAME_OVER_SNAKE_LENGTH = 10;

    /**
     * 游戏结束提示信息
     */
    public String gameOverMessage;
    /**食物的X坐标*/
    public Integer foodX;
    /**食物的Y坐标*/
    public Integer foodY;
    /**食物的x最大范围*/
    public Integer foodXMaxRange;
    /**
     * 食物的y最大范围
     */
    public Integer foodYMaxRange;


    /**
     * 游戏是否开始
     */
    public Boolean isStart = false;
    /**
     * 添加时间计时器
     */
    Timer timer;
    /**
     * 初始化蛇
     */
    MySnake snake;
    /**
     * 生成食物位置的random对象
     */
    Random random;


    /**
     * 初始化函数
      */
    public void init(){
        timer = new Timer(500, this);
        snake = getInitialSnake();
        this.random = new Random();
        foodXMaxRange =GAME_WIDTH/snake.getSize();
        foodYMaxRange =GAME_HEIGHT/snake.getSize();
        /*初始化食物位置*/
        foodX = snake.getSize()*(1+random.nextInt(foodXMaxRange));
        foodY = snake.getSize()*(1+random.nextInt(foodYMaxRange));

    }
    public MyPanel() {
        init();
        /*设置获取焦点为true*/
        this.setFocusable(true);
        /*添加按键监听*/
        this.addKeyListener(this);
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        this.setBackground(Color.gray);
        /*在画布上添加游戏区域*/
        g.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
        FOOD.paintIcon(this,g,foodX,foodY);
        drawSnake(snake, g);
        overGame(g);
        pauseGame(g);

    }

    /**
     * @param snake 蛇的结构信息
     * @param g     Graphics
     * @author chen chao
     * 根据传入的蛇的结构信息画出蛇的身体
     */
    public void drawSnake(MySnake snake, Graphics g) {
        /*画出蛇的身体*/
        ArrayList<SnakeBody> bodies = snake.getSnakeBodies();
        for (int i = 0; i < bodies.size() - 1; i++) {
            BODY.paintIcon(this, g, bodies.get(i).getX() * snake.getSize(), bodies.get(i).getY() * snake.getSize());
        }
        /*画出蛇头*/
        SnakeBody headBody = bodies.get(bodies.size() - 1);
        ImageIcon headIcon;
        if (Math.abs(snake.getXDirection()) > 0) {
            headIcon = (snake.getXDirection() == 1) ? RIGHT : LEFT;
        } else if (Math.abs(snake.getYDirection()) > 0) {
            headIcon = (snake.getYDirection() == 1) ? DOWN : UP;
        } else {
            System.out.println("蛇失去方向,程序出错!");
            return;
        }
        headIcon.paintIcon(this, g, headBody.getX() * snake.getSize(), headBody.getY() * snake.getSize());
    }

    /**
     * @return MySnake类型长度为3的蛇
     * @author chen chao
     * 获取一条初始3长度小蛇
     */
    public static MySnake getInitialSnake() {
        MySnake snake = new MySnake();
        ArrayList<SnakeBody> bodies = new ArrayList<>();
        /*设置蛇的身体大小*/
        snake.setSize(25);
        /*添加身体结构*/
        SnakeBody body0 = new SnakeBody(1, 4);
        SnakeBody body1 = new SnakeBody(2, 4);
        SnakeBody head = new SnakeBody(3, 4);
        bodies.add(0, body0);
        bodies.add(1, body1);
        bodies.add(2, head);
        /*设置方向*/
        snake.setXDirection(1);
        snake.setYDirection(0);
        /*添加身体*/
        snake.setSnakeBodies(bodies);
        return snake;
    }

    /**
     * @param g Graphics
     * @description 判断游戏暂停
     * @author chen chao
     * 暂停游戏的方法，在游戏界面上显示暂停游戏的提示语
     */
    public void pauseGame(Graphics g) {
        if (!isStart) {
            printTip(g, "游戏已暂停，按空格开始！");
        }
    }

    /**
     * @param g Graphics
     * @author chen chao
     * @description 判断游戏暂停
     */
    public void overGame(Graphics g) {
        if (isGameOver()) {
            timer.stop();
            printTip(g, gameOverMessage);
        }

    }

    /**
     * @param g       graphics
     * @param message 提示信息
     * @author chen chao
     * @description 打印游戏提示信息
     */
    public void printTip(Graphics g, String message) {
        g.setColor(Color.white);
        g.setFont(new Font("宋体", Font.BOLD, 50));
        g.drawString(message, 50, 500);
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_SPACE:
                /*如果按下的是空格键则游戏状态取反*/
                isStart = !isStart;
                /*重画组件*/
                repaint();
                break;
            case KeyEvent.VK_UP:
                snake.changeDirection(0, -1);
                break;
            case KeyEvent.VK_DOWN:
                snake.changeDirection(0, 1);
                break;
            case KeyEvent.VK_LEFT:
                snake.changeDirection(-1, 0);
                break;
            case KeyEvent.VK_RIGHT:
                snake.changeDirection(1, 0);
                break;
            default:
                break;
        }
    }
    @Override
    public void keyReleased(KeyEvent e) {
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        /*如果游戏开始则蛇开始移动*/
        if (isStart) {
            if(isEatFood()){
                snake.eatFood();
                /*再次初始化食物位置*/
                foodX = snake.getSize()*(1+random.nextInt(foodXMaxRange));
                foodY = snake.getSize()*(1 +random.nextInt(foodYMaxRange));
            }
            else{
                snake.move();
            }

            /*重画组件*/
            repaint();
            timer.start();
        }
    }
    public Boolean isEatFood(){
        ArrayList<SnakeBody> snakeBodies =snake.getSnakeBodies();
        SnakeBody head =snakeBodies.get(snakeBodies.size() - 1);
        int x = (head.getX() + snake.getXDirection())*snake.getSize();
        int y = (head.getY() + snake.getYDirection())*snake.getSize();
        System.out.println((foodX==x)+"foodX="+foodX+",x="+x);
        System.out.println((foodY==y)+"foodY="+foodY+",y="+y);
        return x==foodX&&y==foodY;
    }
    /**
     * 判断游戏是否结束
     *
     * @return true表示结束，false表示没结束
     */
    public Boolean isGameOver() {
        /*蛇的身体长度大于等于10,游戏结束*/
        if (snake.getSnakeBodies().size() >= GAME_OVER_SNAKE_LENGTH) {
            gameOverMessage = "游戏胜利！";
            return true;
        }
        /*蛇的头部如果超出边界则游戏结束*/
        SnakeBody head = snake.getSnakeBodies().get(snake.getSnakeBodies().size() - 1);
        boolean b = head.getX() * snake.getSize() >= GAME_WIDTH || head.getY() * snake.getSize() >= GAME_HEIGHT || head.getY() < 0 || head.getX() < 0;
        gameOverMessage = "触碰边框，游戏失败！";
        return b;
    }
}
